.text
.global _start
_start:
	/*
	 * Vector table 中断命令存放寄存器 异常向量表
	 */ 
	b reset               @ 0x00
	b .                   @ 0x04
	b .                   @ 0x08
	b .                   @ 0x0c
	b .                   @ 0x10
	b irq_handler         @ 0x14
	b .                   @ 0x18
	b .                   @ 0x1c

reset:
	/*
	 * Set vector address in CP15 VBAR register
	 * 设置起始位 为 0x40008000 
	 */ 
	ldr	r0, =_start
	mcr	p15, 0, r0, c12, c0, 0	@Set VBAR

	/*
	 * Set the cpu to SVC32 mode, Disable FIQ/IRQ
	 * 设置CPU为 SVC 模式 ARM32位 关闭FIQ IRQ模式
	 */  

	mrs r0, cpsr
	bic r0, r0, #0x1f
	orr	r0, r0, #0xd3
	msr	cpsr ,r0

	/*
	 * Defines access permissions for each coprocessor
	 */  
    mov	r0, #0xfffffff
    mcr	p15, 0, r0, c1, c0, 2  	

	/*
	 * Invalidate L1 I/D                                                                                                                   
	 */
	mov	r0, #0					@Set up for MCR
	mcr	p15, 0, r0, c8, c7, 0	@Invalidate TLBs
	mcr	p15, 0, r0, c7, c5, 0	@Invalidate icache
	
	/*
	 * Set the FPEXC EN bit to enable the FPU
	 */ 
	mov r3, #0x40000000
	fmxr FPEXC, r3
	
	/*
	 * Disable MMU stuff and caches
	 */
	mrc	p15, 0, r0, c1, c0, 0
	bic	r0, r0, #0x00002000		@Clear bits 13 (--V-)
	bic	r0, r0, #0x00000007		@Clear bits 2:0 (-CAM)
	orr	r0, r0, #0x00001000		@Set bit 12 (---I) Icache
	orr	r0, r0, #0x00000002		@Set bit 1 (--A-) Align
	orr	r0, r0, #0x00000800		@Set bit 11 (Z---) BTB
	mcr	p15, 0, r0, c1, c0, 0

	/*
	 * Initialize stacks   初始化 各个模式下的 栈                                                                                                               
	 */
init_stack:     
	/*svc mode stack*/
	msr cpsr, #0xd3
	ldr sp, _stack_svc_end

	/*undef mode stack*/
	msr cpsr, #0xdb
	ldr sp, _stack_und_end

	/*abort mode stack*/	
	msr cpsr,#0xd7
	ldr sp,_stack_abt_end

	/*irq mode stack*/	
	msr cpsr,#0xd2
	ldr sp, _stack_irq_end
	
	/*fiq mode stack*/
	msr cpsr,#0xd1
	ldr sp, _stack_fiq_end
	
	/*user mode stack, enable FIQ/IRQ*/
	msr cpsr,#0x10
	ldr sp, _stack_usr_end

	/*Call main*/
	b main

irq_handler:
	/*1.因为产生 IRQ 后自动保存到 LR 的返回地址，它是被 IRQ
	 * 打断的下一条再下一条指令的地址，所以我们要用软件程序给他-4.
	 */

	sub lr, lr, #4

	/*2.因为　IRQ　模式下使用　Ｒ０－Ｒ１２寄存器　是与　USER 模式下一样的
	  *所以在处理异常之前需要先将之前user模式寄存器的值要压栈保护
	 */
	
	stmfd sp!, {r0-r12,lr}

	/*
	 *3.处理异常　跳转指令
	 */
	bl do_irq

	//异常返回
	//r0-r12 出栈　恢复到异常之前的值
	ldmfd sp!, {r0-r12, pc}^


/*
 *定义 每个模式下起始地址
 */
_stack_svc_end:      
	.word stack_svc + 512
_stack_und_end:      
	.word stack_und + 512
_stack_abt_end:      
	.word stack_abt + 512
_stack_irq_end:      
    .word stack_irq + 512
_stack_fiq_end:
    .word stack_fiq + 512
_stack_usr_end:      
    .word stack_usr + 512

/*
 *定义 每个模式下 栈空间512 
 */
.data
stack_svc:      
	.space 512
stack_und:
	.space 512
stack_abt:      
	.space 512
stack_irq:      
	.space 512
stack_fiq:      
	.space 512
stack_usr:      
	.space 512
